#ifndef __TRIANGLE_MESH_NURBS__
#define __TRIANGLE_MESH_NURBS__

#include "mesh.h"
#include "dispatcher.h"

class Node;
class SEdge;
#include "triangle.h"

class STriangleMesh : public Mesh {
public:
	STriangleMesh() {};
	STriangleMesh(size_t nodes, 
				  const std::vector< std::pair<std::string, Variant> >& vertexdata, 
				  const std::vector< std::pair<std::string, Variant> >& triangledata, 
				  const std::vector<math::Vec3ui>& triangleIndex);
	STriangleMesh(const std::vector<Vec3n>& vertex, const std::vector< std::vector<size_t> >& index);
	STriangleMesh(const std::vector<Vec3n>& vertex, const std::vector<size_t>& index);
	STriangleMesh(const std::vector<Vec3n>& vertex, const std::vector<math::Vec3ui>& index);
	~STriangleMesh();

	void Init(size_t nodes, 
				  const std::vector< std::pair<std::string, Variant> >& vertexdata, 
				  const std::vector< std::pair<std::string, Variant> >& triangledata, 
				  const std::vector<math::Vec3ui>& triangleIndex);

	virtual Node* GetNode(size_t i) {return vertex[i];}
	virtual const Node* GetNode(size_t i) const {return vertex[i];}

	virtual Element* GetElement(size_t i) {return triangle[i];}
	virtual const Element* GetElement(size_t i) const {return triangle[i];}

	virtual size_t SizeNodes() const {return vertex.size();}
	virtual size_t SizeElements() const {return triangle.size();}

	size_t GetNumVertices() const {return SizeNodes();}
	size_t GetNumEdges() const {return edge.size();}
	size_t GetNumTriangles() const {return SizeElements();}

	Node* AllocateVertex();
	SEdge* AllocateEdge();
	STriangle* AllocateTriangle(Node* v0, Node* v1, Node* v2);
	
	template<typename T>
	void AddEdgeAttribute(const std::string& attribute, const T& t) {
		std::vector<T> x(GetNumEdges(), t);
		edgeAttribute.Add(attribute, x);
	}

	SEdge* LookUp(Node* a, Node* b);
	
	std::vector<STriangle*> GetRing(Node* v);
	void GetRing(Node* v, std::vector<SEdge*>& e);

	std::vector<Node*> GetBoundary(size_t i);
	size_t GetBoundarySize() const {return boundaryn.size();}
	size_t GetBoundaryIndex(Node* v) const;

	Node* Find(const Vec3n& P, const std::string& attribute, nfloat e = 0.00001);
	bool Find(std::vector<Node*>& Q, const Vec3n& P, const std::string& attribute, nfloat e = 0.00001);
	Node* FindClosest(const Vec3n& P, const std::string& attribute);

	bool IsBoundaryVertex(Node* v);

	std::vector<STriangle*> Neighborhood(const Vec3n& P) {return std::vector<STriangle*>();}//tree.Query(P);}
	
	virtual void Save(const std::string& filename, const std::string& attribute) const;

	Node* Vertex(size_t i) {return static_cast<Node*>(GetNode(i));}
	SEdge* Edge(size_t i) {return edge.at(i);}
	STriangle* Triangle(size_t i) {return static_cast<STriangle*>(GetElement(i));}

	const Node* Vertex(size_t i) const {return static_cast<const Node*>(GetNode(i));}
	const SEdge* Edge(size_t i) const {return edge.at(i);}
	const STriangle* Triangle(size_t i) const {return static_cast<const STriangle*>(GetElement(i));}

	nfloat Area(Node* v, const std::string& attribute);

	virtual void Dispatch(Dispatcher* d) {
		d->Visit(this);
	}
private:
	Node* ExtractMin(const std::vector<nfloat>& D, std::vector<bool>& F);
	void SortNeighbors(Node* v, std::list<size_t>& trianglelist);
	bool Map(Node* a, Node* b, SEdge* e);
	bool UnMap(Node* a, Node* b);
	void ComputeBoundary();

	std::vector<Node*> vertex;
	std::vector<SEdge*> edge;
	std::vector<STriangle*> triangle;

	std::vector< std::vector<Node*> > boundaryn;

	std::map< std::pair<size_t, size_t>, SEdge*> mapEdge;
	size_t vertexidcounter, edgeidcounter, triangleidcounter;
	Attribute edgeAttribute;
};

#endif //__TRIANGLE_MESH_NURBS__
